#!/bin/bash
# /usr/lib/check_mk_agent/local/300/check_adguard

set -u

CONFIG="/etc/check_mk/adguard.conf"

OK=0
WARN=1
CRIT=2
UNKNOWN=3

#
# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
#

if [[ ! -r "$CONFIG" ]]; then
    printf '%s\n' \
        "${UNKNOWN} \"AdGuard Home\" - Configuration file ${CONFIG} missing or unreadable"
    exit 0
fi

# shellcheck disable=SC1090
source "$CONFIG"

ADGUARD_URL="${ADGUARD_URL:-http://127.0.0.1:3000}"
ADGUARD_USER="${ADGUARD_USER:-}"
ADGUARD_PASSWORD="${ADGUARD_PASSWORD:-}"

CHECK_UPDATES="${CHECK_UPDATES:-yes}"
ALERT_PROTECTION_DISABLED="${ALERT_PROTECTION_DISABLED:-yes}"

#
# ---------------------------------------------------------------------------
# Requirements
# ---------------------------------------------------------------------------
#

if ! command -v curl >/dev/null 2>&1; then
    printf '%s\n' \
        "${UNKNOWN} \"AdGuard Home\" - curl is not installed"
    exit 0
fi

if ! command -v jq >/dev/null 2>&1; then
    printf '%s\n' \
        "${UNKNOWN} \"AdGuard Home\" - jq is not installed"
    exit 0
fi

#
# ---------------------------------------------------------------------------
# curl configuration
# ---------------------------------------------------------------------------
#

CURL_OPTS=(
    --silent
    --show-error
    --fail
    --connect-timeout 3
    --max-time 10
)

AUTH_OPTS=()

if [[ -n "$ADGUARD_USER" ]]; then
    AUTH_OPTS=(
        --user "${ADGUARD_USER}:${ADGUARD_PASSWORD}"
    )
fi

#
# ---------------------------------------------------------------------------
# AdGuard status / version
# ---------------------------------------------------------------------------
#

STATUS_RESPONSE="$(
    curl \
        "${CURL_OPTS[@]}" \
        "${AUTH_OPTS[@]}" \
        "${ADGUARD_URL%/}/control/status" \
        2>/dev/null
)"

STATUS_RC=$?

if [[ $STATUS_RC -ne 0 || -z "$STATUS_RESPONSE" ]]; then
    printf '%s\n' \
        "${CRIT} \"AdGuard Home\" - API unavailable or authentication failed at ${ADGUARD_URL}"
    exit 0
fi

if ! printf '%s' "$STATUS_RESPONSE" |
    jq -e 'type == "object"' >/dev/null 2>&1
then
    printf '%s\n' \
        "${UNKNOWN} \"AdGuard Home\" - Status API returned unexpected data"
    exit 0
fi

VERSION="$(
    printf '%s' "$STATUS_RESPONSE" |
        jq -r '.version // empty'
)"

RUNNING="$(
    printf '%s' "$STATUS_RESPONSE" |
        jq -r '.running // false'
)"

PROTECTION_ENABLED="$(
    printf '%s' "$STATUS_RESPONSE" |
        jq -r '.protection_enabled // false'
)"

DNS_PORT="$(
    printf '%s' "$STATUS_RESPONSE" |
        jq -r '.dns_port // 53'
)"

DNS_ADDRESSES="$(
    printf '%s' "$STATUS_RESPONSE" |
        jq -r '
            (.dns_addresses // [])
            | join(", ")
        '
)"

if [[ "$RUNNING" != "true" ]]; then
    printf '%s\n' \
        "${CRIT} \"AdGuard Home\" - API reachable but DNS service reports not running"
else
    if [[ -n "$VERSION" ]]; then
        printf '%s\n' \
            "${OK} \"AdGuard Home\" - API reachable, DNS running, version ${VERSION}, port ${DNS_PORT}"
    else
        printf '%s\n' \
            "${OK} \"AdGuard Home\" - API reachable, DNS running, port ${DNS_PORT}"
    fi
fi

#
# ---------------------------------------------------------------------------
# Protection state
# ---------------------------------------------------------------------------
#

if [[ "$PROTECTION_ENABLED" == "true" ]]; then

    printf '%s\n' \
        "${OK} \"AdGuard Protection\" - Protection enabled"

else

    if [[ "$ALERT_PROTECTION_DISABLED" == "yes" ]]; then
        printf '%s\n' \
            "${WARN} \"AdGuard Protection\" - Protection disabled"
    else
        printf '%s\n' \
            "${OK} \"AdGuard Protection\" - Protection disabled"
    fi

fi

#
# ---------------------------------------------------------------------------
# Statistics
# ---------------------------------------------------------------------------
#

STATS_RESPONSE="$(
    curl \
        "${CURL_OPTS[@]}" \
        "${AUTH_OPTS[@]}" \
        "${ADGUARD_URL%/}/control/stats" \
        2>/dev/null
)"

STATS_RC=$?

if [[ $STATS_RC -ne 0 || -z "$STATS_RESPONSE" ]]; then

    printf '%s\n' \
        "${UNKNOWN} \"AdGuard Statistics\" - Unable to retrieve DNS statistics"

elif ! printf '%s' "$STATS_RESPONSE" |
    jq -e 'type == "object"' >/dev/null 2>&1
then

    printf '%s\n' \
        "${UNKNOWN} \"AdGuard Statistics\" - Statistics API returned unexpected data"

else

    DNS_QUERIES="$(
        printf '%s' "$STATS_RESPONSE" |
            jq -r '.num_dns_queries // 0'
    )"

    BLOCKED="$(
        printf '%s' "$STATS_RESPONSE" |
            jq -r '.num_blocked_filtering // 0'
    )"

    SAFE_BROWSING="$(
        printf '%s' "$STATS_RESPONSE" |
            jq -r '.num_replaced_safebrowsing // 0'
    )"

    SAFE_SEARCH="$(
        printf '%s' "$STATS_RESPONSE" |
            jq -r '.num_replaced_safesearch // 0'
    )"

    PARENTAL="$(
        printf '%s' "$STATS_RESPONSE" |
            jq -r '.num_replaced_parental // 0'
    )"

    AVG_TIME="$(
        printf '%s' "$STATS_RESPONSE" |
            jq -r '.avg_processing_time // 0'
    )"

    [[ "$DNS_QUERIES" =~ ^[0-9]+$ ]] || DNS_QUERIES=0
    [[ "$BLOCKED" =~ ^[0-9]+$ ]] || BLOCKED=0
    [[ "$SAFE_BROWSING" =~ ^[0-9]+$ ]] || SAFE_BROWSING=0
    [[ "$SAFE_SEARCH" =~ ^[0-9]+$ ]] || SAFE_SEARCH=0
    [[ "$PARENTAL" =~ ^[0-9]+$ ]] || PARENTAL=0
    [[ "$AVG_TIME" =~ ^[0-9]+([.][0-9]+)?$ ]] || AVG_TIME=0

    BLOCK_PERCENT="$(
        awk \
            -v blocked="$BLOCKED" \
            -v total="$DNS_QUERIES" \
            'BEGIN {
                if (total > 0) {
                    printf "%.2f", (blocked / total) * 100
                } else {
                    printf "0.00"
                }
            }'
    )"

    #
    # avg_processing_time is reported in seconds.
    #

    AVG_TIME_MS="$(
        awk \
            -v seconds="$AVG_TIME" \
            'BEGIN {
                printf "%.3f", seconds * 1000
            }'
    )"

    printf '%s\n' \
        "${OK} \"AdGuard Statistics\" queries=${DNS_QUERIES};;;0|blocked=${BLOCKED};;;0|blocked_percent=${BLOCK_PERCENT}%;;;0;100|avg_processing_time=${AVG_TIME_MS}ms;;;0 ${DNS_QUERIES} queries, ${BLOCKED} blocked (${BLOCK_PERCENT}%), average processing ${AVG_TIME_MS} ms"

fi

#
# ---------------------------------------------------------------------------
# AdGuard update check
# ---------------------------------------------------------------------------
#
# AdGuard Home provides its own update-information endpoint.
# This is preferable to independently scraping GitHub because it follows
# AdGuard's own release/update logic.
#

if [[ "$CHECK_UPDATES" == "yes" ]]; then

    VERSION_RESPONSE="$(
        curl \
            "${CURL_OPTS[@]}" \
            "${AUTH_OPTS[@]}" \
            -X POST \
            -H "Content-Type: application/json" \
            -d '{"recheck_now":true}' \
            "${ADGUARD_URL%/}/control/version.json" \
            2>/dev/null
    )"

    VERSION_RC=$?

    if [[ $VERSION_RC -ne 0 || -z "$VERSION_RESPONSE" ]]; then

        printf '%s\n' \
            "${UNKNOWN} \"AdGuard Update\" - Installed ${VERSION:-unknown}, unable to retrieve update information"

    elif ! printf '%s' "$VERSION_RESPONSE" |
        jq -e 'type == "object"' >/dev/null 2>&1
    then

        printf '%s\n' \
            "${UNKNOWN} \"AdGuard Update\" - Update API returned unexpected data"

    else

        UPDATE_DISABLED="$(
            printf '%s' "$VERSION_RESPONSE" |
                jq -r '.disabled // false'
        )"

        NEW_VERSION="$(
            printf '%s' "$VERSION_RESPONSE" |
                jq -r '.new_version // empty'
        )"

        NEW_VERSION="${NEW_VERSION#v}"
        INSTALLED_VERSION="${VERSION#v}"

        if [[ "$UPDATE_DISABLED" == "true" ]]; then

            printf '%s\n' \
                "${OK} \"AdGuard Update\" - Update checking disabled by AdGuard Home, installed ${INSTALLED_VERSION:-unknown}"

        elif [[ -z "$NEW_VERSION" ]]; then

            printf '%s\n' \
                "${OK} \"AdGuard Update\" - Current: installed ${INSTALLED_VERSION:-unknown}"

        elif [[ -z "$INSTALLED_VERSION" ]]; then

            printf '%s\n' \
                "${WARN} \"AdGuard Update\" - New version ${NEW_VERSION} available, installed version unknown"

        elif [[ "$NEW_VERSION" == "$INSTALLED_VERSION" ]]; then

            printf '%s\n' \
                "${OK} \"AdGuard Update\" - Current: installed ${INSTALLED_VERSION}"

        else

            printf '%s\n' \
                "${WARN} \"AdGuard Update\" - Update available: installed ${INSTALLED_VERSION}, latest ${NEW_VERSION}"

        fi
    fi
fi

exit 0